<?php
require_once 'common.php';
require_once 'OaDeveloperModel.php';
require_once 'OaAppModel.php';
require_once 'OaCodeModel.php';
require_once 'OaAuthorityModel.php';
require_once OPEN_LIB_PATH . '/open/business-logic/OaSyncInfoLogic.php';
require_once OA_LIB_PATH . '/inner/service/OASApi.php';

/**
 * 公司模型
 * @author wangjiajun
 *
 */
class OaCompanyModel extends OpModel
{
    // 公司状态
    const COMPANY_STATUS_CREATED = 0;         // 新创建
    const COMPANY_STATUS_AUDIT_OK = 1;        // 审核通过 
    const COMPANY_STATUS_AUDIT_FAIL = 2;      // 审核未通过
    
    // 接入审核状态
    const JOIN_STATUS_APPLY_NO = 0;            // 未申请
    const JOIN_STATUS_APPLY_YES = 1;           // 已申请
    const JOIN_STATUS_AUDIT_OK = 2;            // 审核通过
    const JOIN_STATUS_AUDIT_FAILED = 3;        // 审核未通过
    
    // 上线审核状态
    const RELEASE_STATUS_APPLY_NO = 0;            // 未申请
    const RELEASE_STATUS_APPLY_YES = 1;           // 已申请
    const RELEASE_STATUS_AUDIT_OK = 2;            // 审核通过
    const RELEASE_STATUS_AUDIT_FAILED = 3;        // 审核未通过
    
    // 证件类型
    const CERTIFICATE_TYPE_ID_CARD = 1;        // 身份证
    
    // 公司资质
    const COMPANY_GRADE_NORMAL = 0;        // 普通
    const COMPANY_GRADE_SENIOR = 1;        // 高级
    const COMPANY_GRADE_TRUSTED = 2;       // 信任
    const COMPANY_GRADE_NEW = 100;         // 新用户
    const COMPANY_GRADE_UNTRUSTED = 127;   // 非信任
    
    // 公司成员邀请状态
    const COMPANY_INVITE_STATUS_NEW = 0;        // 新邀请
    const COMPANY_INVITE_STATUS_ACCEPTED = 1;   // 已接受
    const COMPANY_INVITE_STATUS_INVALID = 2;    // 已失效
    
    private $_oaWebDb;
    private $_companyTable;
    private $_appTable;
    private $_companyDeveloperTable;
    private $_inviteSndaUserTable;
    
    public static function getConstantValueByName($name, $default = 0)
    {
        return self::_getConstByName($name, '', $default, 'OaCompanyModel');
    }
    
    public function __construct($logger = null)
    {
        if (is_null($logger)) {
            $logger = getOaModelLogger();
        }
        parent::__construct($logger);
        $dbConfig = Oa_Util_Config::getSingleDbConfig(OA_WEB_DB_CLUSTER_ID);
        $db = OpDbModel::getInstance($dbConfig, $logger);
        $this->_oaWebDb = $db;
        $this->_companyTable = new OpTableModel($db, 'company', $logger);
        $this->_appTable = new OpTableModel($db, 'app', $logger);
        $this->_companyDeveloperTable = new OpTableModel($db, 'company_developer', $logger);
        $this->_inviteSndaUserTable = new OpTableModel($db, 'invite_snda_user', $logger);
    }
    
    /**
     * 创建公司
     * @param string $name
     * @param string $pt
     * @param array $row
     * @return int|boolean 如果pt帐号不存在，设置错误号1；如果名称重复，设置错误号2
     */
    public function createCompany($name, $pt, $row = array())
    {
        $result = User::convertId($pt);
        if ($result[0] != 0) {
            $this->_setError(1, "convert id failed: {$result[1]}");
            return false;
        }
        $creator = $result[2];    
        $codeModel = new OaCodeModel($this->_logger);
        if (is_array($this->getCompanyByName($name)) || 
        	is_array($codeModel->getCompanyByName($name, OaAppModel::APP_CONFIG_ENV_PRODUCTION))) {
            $this->_setError(2, "company name already exists");
            return false;
        }
        $row = array_merge(array(
            'name' => $name,
            'creator' => $creator,
            'status' => self::COMPANY_STATUS_AUDIT_OK,
            'grade' => self::COMPANY_GRADE_NORMAL,
            'legal_person_cert_type' => self::CERTIFICATE_TYPE_ID_CARD,
            'contract_begin_time' => date('Y-m-d H:i:s'),
            'contract_end_time' => date('Y-m-d H:i:s'),
            'create_time' => date('Y-m-d H:i:s')
        ), $row);
        if (isset($row['other_info'])) {
            $row['other_info'] = json_encode($row['other_info']);
        }
        $companyId = $this->_companyTable->insert($row);
        if ($companyId === false) {
            $this->_logger->log("insert failed");
            return false;
        }
        
        if (!OaSyncInfoLogic::syncCompanyInfo($companyId, 'add', OaAppModel::APP_CONFIG_ENV_TEST) || 
            !OaSyncInfoLogic::syncCompanyInfo($companyId, 'add', OaAppModel::APP_CONFIG_ENV_PRODUCTION)) {
        	$this->_companyTable->delete(array(
        	    'id' => $companyId
        	));
        	$this->_logger->log("sync company info failed");
        	return false;
        }
        
        if ($this->addDeveloper($companyId, $pt, OaAuthorityModel::ROLE_COMPANY_ADMIN, $creator) === false) {
            $this->_logger->log("add developer failed");
            return false;
        }
        
        return $companyId;
    }
    
    /**
     * 查询某个公司
     * @param int $companyId
     * @param array $columns
     * @return array|boolean
     */
    public function getCompany($companyId, $columns = null)
    {
        $row = $this->_companyTable->getRow(array('id' => $companyId), null, $columns);
        if (is_array($row) && isset($row['other_info'])) {
            $row['other_info'] = json_decode($row['other_info'], true);
        }
        return $row;
    }
    
    /**
     * 根据名称查询公司
     * @param string $name
     * @return array|null|boolean
     */
    public function getCompanyByName($name)
    {
        $companys = $this->getCompanyList(array(
            'name' => $name
        ));
        if ($companys === false) {
        	return false;
        }
        if (count($companys) > 0) {
        	return $companys[0];
        } else {
        	return null;
        }
    }
    
    /**
     * 查询多个公司，返回数组以公司ID为Index
     * @param array $companyIds
     * @return array|boolean
     */
    public function getCompanyMulti($companyIds)
    {
        if (empty($companyIds)) {
            return array();
        }
        foreach ($companyIds as &$companyId) {
            $companyId = (int) $companyId;
        }
        unset($companyId);
        $sql = "SELECT * FROM company WHERE id IN (" . implode(',', $companyIds) . ")";
        $rows = $this->_companyTable->query($sql);
        if ($rows === false) {
            $this->_logger->log("query failed");
            return false;
        }
        $companys = array();
        foreach ($rows as $row) {
            if (isset($row['other_info'])) {
                $row['other_info'] = json_decode($row['other_info'], true);
            }
            $companys[$row['id']] = $row;
        }
        return $companys;
    }
    
    /**
     * 查询公司资质
     * @param int $companyId
     * @return int|boolean
     */
    public function getCompanyGrade($companyId)
    {
        $company = $this->getCompany($companyId, array('grade'));
        if ($company === null) {
            $this->_logger->log("company not exists");
            return false;
        }
        return $company['grade'];
    }
    
    /**
     * 根据指定条件查询公司列表
     * @param array $where
     * @param int $offset
     * @param int $count
     * @param string $sort
     * @param array $otherWhere
     * @return array|boolean
     */
    public function getCompanyList($where = null, $offset = 0, $count = null, 
        $sort = null, $otherWhere = null)
    {
        $rows = $this->_companyTable->get($where, $offset, $count, $sort, $otherWhere);
        if (is_array($rows)) {
            foreach ($rows as &$row) {
                if (isset($row['other_info'])) {
                    $row['other_info'] = json_decode($row['other_info'], true);
                }
            }
        }
        return $rows;
    }
    
    /**
     * 根据指定条件查询公司总数
     * @param array $where
     * @param array $otherWhere
     * @return int|boolean
     */
    public function getCompanyListCount($where = null, $otherWhere = null)
    {
        $sql = "SELECT COUNT(*) FROM company" . getSqlCond($where, null, null, null, $otherWhere);
        $row = $this->_companyTable->query($sql, PDO::FETCH_NUM);
        if ($row === false) {
            $this->_logger->log("query failed");
            return false;
        }
        return (int) $row[0][0];
    }
    
    /**
     * 修改某个公司的信息
     * @param int $companyId
     * @param array $row
     * @return boolean 如果名称重复，设置错误号1
     */
    public function modifyCompany($companyId, $row)
    {
    	$company = $this->getCompany($companyId);
    	if (!is_array($company)) {
    		$this->_logger("company not exists: company-$companyId");
    		return false;
    	}
    	if (isset($row['name']) && $row['name'] == $company['name']) {
    		unset($row['name']);
    	}
    	if (empty($row)) {
    		return true;
    	}
    	if (isset($row['name'])) {
	    	$codeModel = new OaCodeModel($this->_logger);
	        if (is_array($this->getCompanyByName($row['name'])) || 
	        	is_array($codeModel->getCompanyByName($row['name'], OaAppModel::APP_CONFIG_ENV_PRODUCTION))) {
	            $this->_setError(1, "company name already exists");
	            return false;
	        }
    	}
        if (isset($row['other_info'])) {
            $row['other_info'] = json_encode($row['other_info']);
        }
        if (!$this->_companyTable->update(array('id' => $companyId), $row)) {
        	$this->_logger->log("update failed");
        	return false;
        }
        
        if (!OaSyncInfoLogic::syncCompanyInfo($companyId, 'update', OaAppModel::APP_CONFIG_ENV_TEST) || 
            !OaSyncInfoLogic::syncCompanyInfo($companyId, 'update', OaAppModel::APP_CONFIG_ENV_PRODUCTION)) {
        	$this->_logger->log("sync company info failed");
        	return false;
        }
        
        return true;
    }
    
    /**
     * 设置公司资质
     * @param int $companyId
     * @param int $grade
     * @return boolean
     */
    public function setCompanyGrade($companyId, $grade)
    {
        return $this->modifyCompany($companyId, array(
            'grade' => $grade
        ));
    }
    
    /**
     * 添加员工
     * @param int $companyId
     * @param string $pt
     * @param int $role
     * @return boolean 如果pt帐号不存在，设置错误号1；如果已经在公司中，设置错误号2
     */
    public function addDeveloper($companyId, $pt, $role = OaAuthorityModel::ROLE_COMPANY_EMPLOYEE)
    {
        $result = User::convertId($pt);
        if ($result[0] != 0) {
            $this->_setError(1, "convert id failed: {$result[1]}");
            return false;
        }
        $developerId = $result[2];
        // 如果还不是开发者，先添加到开发者表里
        $developerModel = new OaDeveloperModel($this->_logger);
        $developer = $developerModel->getDeveloper($developerId);
        if (is_null($developer)) {
            if ($developerModel->createDeveloper($developerId, $pt, '') === false) {
                return false;
            }
            $developer = $developerModel->getDeveloper($developerId);
        }
        
        // 自动把该开发者加到测试人员表里废弃
//        if ($developerModel->getTestAccount($pt) === null && 
//            $developerModel->addTestAccount($pt) === false) {
//            $this->_logger->log("add test account failed");
//            return false;
//        }
        
        // 不允许重复添加
        if (is_array($this->getDeveloper($companyId, $developerId))) {
            $this->_setError(2, "already in company");
            return false;
        }
        
        return $this->_companyDeveloperTable->insert(array(
            'company_id' => $companyId,
            'developer_id' => $developerId,
            'role' => $role
        ), null, false);
    }
    
    /**
     * 查询开发者
     * @param int $companyId
     * @param int $developerId
     * @return array|null|boolean
     */
    public function getDeveloper($companyId, $developerId)
    {
        return $this->_companyDeveloperTable->getRow(array(
            'company_id' => $companyId,
            'developer_id' => $developerId
        ));
    }
    
    /**
     * 查询公司管理员
     * @param int $companyId
     * @return array|null|boolean
     */
    public function getCompanyAdmin($companyId)
    {
    	$developers = $this->getCompanyDeveloperList(array(
        	'company_id' => $companyId,
    		'role' => OaAuthorityModel::ROLE_COMPANY_ADMIN
    	));
    	if ($developers === false) {
    		return false;
    	}
    	if (count($developers) > 0) {
    		return $developers[0];
    	} else {
    		return null;
    	}
    }
    
    /**
     * 根据角色查询公司员工
     * @param int $companyId
     * @param int $role 在公司中的角色，null表示任意角色
     * @param int $offset
     * @param int|null $count null返回全部
     * @return array|boolean
     */
    public function getCompanyDevelopers($companyId, $role = null, $offset = 0, $count = null)
    {
        $where = array(
        	'company_id' => $companyId
        );
        if (!is_null($role)) {
            $where['role'] = $role;
        }
        return $this->getCompanyDeveloperList($where, $offset, $count);
    }
    
    /**
     * 根据指定条件查询公司开发者列表
     * @param array $where
     * @param int $offset
     * @param int $count
     * @param string $sort
     * @param array $otherWhere
     * @return array|boolean
     */
    public function getCompanyDeveloperList($where = null, $offset = 0, $count = null, 
        $sort = null, $otherWhere = null)
    {
        $sql = "SELECT t1.*, t2.pt, t2.name 
        	FROM company_developer t1 LEFT JOIN developer t2 ON (t1.developer_id=t2.uid) " . 
        	getSqlCond($where, $offset, $count, $sort, $otherWhere);
        return $this->_oaWebDb->query($sql);
    }
    
    /**
     * 根据指定条件查询公司开发者总数
     * @param array $where
     * @param array $otherWhere
     * @return int|boolean
     */
    public function getCompanyDeveloperListCount($where = null, $otherWhere = null)
    {
        $sql = "SELECT COUNT(*) FROM company_developer" . getSqlCond($where, null, null, null, $otherWhere);
        $row = $this->_oaWebDb->query($sql, PDO::FETCH_NUM);
        if ($row === false) {
            $this->_logger->log("query failed");
            return false;
        }
        return (int) $row[0][0];
    }
    
    /**
     * 修改员工角色
     * 
     * @param int $companyId
     * @param int $developerId
     * @param int $role
     * @return boolean 如果该员工不存在，设置错误号1
     */
    public function changeDeveloperRole($companyId, $developerId, $role)
    {
        if (!is_array($this->getDeveloper($companyId, $developerId))) {
            $this->_setError(1, "not a employee");
            return false;
        }
        // 判断新角色是否是管理员
        if ($role == OaAuthorityModel::ROLE_COMPANY_ADMIN) {
            // 原管理员自动变为产品经理
            $rows = $this->getCompanyDevelopers($companyId, OaAuthorityModel::ROLE_COMPANY_ADMIN);
            if ($rows && !$this->changeDeveloperRole($companyId, $rows[0]['developer_id'], 
                OaAuthorityModel::ROLE_COMPANY_PM)) {
                $this->_logger->log("change admin to pm failed");
                return false;
            }
        }
        return $this->_companyDeveloperTable->update(array(
            'company_id' => $companyId,
            'developer_id' => $developerId
        ), array(
            'role' => $role
        ));
    }
    
    /**
     * 替换管理员
     * @param int $appId
     * @param string $pt
     * @return boolean 如果pt帐号不存在，设置错误号1，如果不是公司成员，设置错误号2
     */
    public function changeAdmin($companyId, $pt)
    {
        $result = User::convertId($pt);
        if ($result[0] != 0) {
            $this->_setError(1, "convert id failed: {$result[1]}");
            return false;
        }
        $developerId = $result[2];
        if (!$this->changeDeveloperRole($companyId, $developerId, OaAuthorityModel::ROLE_COMPANY_ADMIN)) {
            if ($this->getErrorNo() == 1) {
                $this->_setError(2, "not a company member");
            } else {
                $this->_logger->log("change developer role failed");
            }
            return false;
        } else {
            return true;
        }
    }
    
    /**
     * 删除员工，同时会从公司下的应用中删除该员工
     * @param int $companyId
     * @param int $developerId
     * @return boolean
     */
    public function deleteDeveloper($companyId, $developerId)
    {
        // 从公司应用中删除该员工
        $appModel = new OaAppModel(OaAppModel::APP_CONFIG_ENV_PRODUCTION, $this->_logger);
        $apps = $appModel->getCompanyApps($companyId);
        foreach ($apps as $app) {
            if (!$appModel->deleteDeveloper($app['id'], $developerId)) {
                $this->_logger->log("delete developer failed");
                return false;
            }
        }
        return $this->_companyDeveloperTable->delete(array(
            'company_id' => $companyId,
            'developer_id' => $developerId
        ));
    }
    
    /**
     * 获取公司应用列表
     * @param int $companyId
     * @param int $offset
     * @param int|null $count null返回全部
     * @param boolean $isDelete 是否包含删除状态应用（默认不包含）
     * @return array|boolean
     */
    public function getCompanyApps($companyId, $offset = 0, $count = null, $isDelete=false)
    {
        $otherWhere = array();
        if(!$isDelete){
            $otherWhere['status'] = array(
            	'key'=>'status', 
            	'operation'=>'>', 
            	'value'=>OaAppModel::APP_STATUS_DELETE
            );
        }
        $sql = "SELECT * FROM app" . getSqlCond(array(
        	'company_id' => $companyId
        ), $offset, $count, 'id ASC', $otherWhere);
        return $this->_appTable->query($sql);
    }
    
    /**
     * 邀请盛大用户加入公司
     * @param string $pt 盛大通行证
     * @param int $companyId
     * @param int $developerId 邀请者
     * @param string $role
     * @return int|boolean
     */
    public function inviteSndaUser($pt, $companyId, $developerId, $role = OaAuthorityModel::ROLE_COMPANY_EMPLOYEE)
    {
        // 将之前发给用户的邀请都设为无效
        if (!$this->_inviteSndaUserTable->update(array(
            'type' => 1,
            'company_id' => $companyId,
            'pt' => $pt
        ), array(
            'status' => self::COMPANY_INVITE_STATUS_INVALID
        ))) {
            $this->_logger->log("update failed");
            return false;
        }
        
        return $this->_inviteSndaUserTable->insert(array(
            'pt' => $pt,
            'developer_id' => $developerId,
            'type' => 1,
            'company_id' => $companyId,
            'role' => $role,
            'status' => self::COMPANY_INVITE_STATUS_NEW,
            'create_time' => date('Y-m-d H:i:s')
        ));
    }
    
    /**
     * 查询邀请记录
     * @param int $id
     * @return array|null|boolean
     */
    public function getInvite($id)
    {
    	return $this->_inviteSndaUserTable->getRow(array(
            'id' => $id
    	));
    }
    
    /**
     * 获取邀请码
     * @param int $id 邀请记录ID
     * @return string|boolean
     */
    public function getInviteToken($id)
    {
        $row = $this->_inviteSndaUserTable->getRow(array(
            'id' => $id
        ));
        if (!$row) {
            $this->_logger->log("invite not exist");
            return false;
        }
        return sha1($row['id'] . $row['pt'] . $row['developer_id'] . $row['company_id'] . 
            $row['create_time']);
    }
    
    /**
     * 接受邀请
     * @param int $id
     * @param string $token
     * @return boolean 如果token错误，设置错误号1；如果已经接受过，设置错误号2；
     * 		如果已在公司中，设置错误号3；如果邀请已失效，设置错误号4
     */
    public function acceptInvite($id, $token)
    {
        if ($token != $this->getInviteToken($id)) {
            $this->_setError(1, "invalid token");
            return false;
        }
        $row = $this->_inviteSndaUserTable->getRow(array(
            'id' => $id
        ));
        if ($row['status'] == self::COMPANY_INVITE_STATUS_ACCEPTED) {
            $this->_setError(2, "already accept");
            return false;
        } else if ($row['status'] == self::COMPANY_INVITE_STATUS_INVALID) {
            $this->_setError(4, "invite is invalid");
            return false;
        }
        if (!$this->setInviteStatus($id, self::COMPANY_INVITE_STATUS_ACCEPTED)) {
            $this->_logger->log("set invite status failed");
            return false;
        }
        if (!$this->addDeveloper($row['company_id'], $row['pt'], $row['role'])) {
            if ($this->getErrorNo() == 2) {
                $this->_setError(3, "already in company");
                return false;
            } else {
                $this->_logger->log("add developer by pt failed");
                return false;
            }
        }
        return true;
    }
    
    /**
     * 修改邀请状态
     * @param int $id
     * @param int $status
     * @return boolean
     */
    public function setInviteStatus($id, $status)
    {
        return $this->_inviteSndaUserTable->update(array(
            'id' => $id
        ), array(
            'status' => $status
        ));
    }
}
